package com.yzf.enterprise.framework.config;

import com.fasterxml.jackson.annotation.JsonValue;
import com.yzf.enterprise.common.utils.ClassUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yuyue
 * @version 2020/4/1 17:46
 */
public interface CodedEnum<T extends Enum<T> & CodedEnum<T>> {
    /**
     * 使用jackson序列化/反序列化时枚举对应的值
     * 如果想要保留原来从字面量反序列化回枚举类的功能，
     * 需要自定义一个 @JsonCreator 的构造/静态工厂方法
     *
     * @return 自定义枚举code
     */
    int getCode();

    @JsonValue
    String getDesc();

    /**
     * WARNING: 禁止在子类之外的调用方调用
     */
    @SuppressWarnings("unchecked")
    static <T extends Enum<T> & CodedEnum<T>> T create(String name) {
        //Class<T> clz = (Class<T>) MethodHandles.lookup().lookupClass();
        //Class<T> clz = (Class<T>) new Object(){}.getClass().getEnclosingClass();
        Class<T> clz = (Class<T>) ClassUtil.getCallerClz();
        try {
            return Enum.valueOf(clz, name);
        } catch (IllegalArgumentException e) {
            if (NumberUtils.isCreatable(name)) {
                int code = Integer.parseInt(name);
                for (T value : clz.getEnumConstants()) {
                    if (value.getCode() == code) {
                        return value;
                    }
                }
            } else {
                for (T value : clz.getEnumConstants()) {
                    if (StringUtils.equalsIgnoreCase(value.getDesc(), name)) {
                        return value;
                    }
                }
            }
        }
        return null;//返回空，自己做判断
    }

    ///**
    // * WARNING: 禁止在子类之外的调用方调用
    // */
    //@SuppressWarnings("unchecked")
    //static <T extends Enum<T> & CodedEnum<T>> Map<Integer, String> getMap() {
    //    Class<T> clz = (Class<T>) ClassUtil.getCallerClz();
    //    Map<Integer, String> map = new HashMap<>();
    //    for (T enumConstant : clz.getEnumConstants()) {
    //        map.put(enumConstant.getCode(), enumConstant.getDesc());
    //    }
    //    return map;
    //}

    static <T extends Enum<T> & CodedEnum<T>> Map<Integer, String> getMap(Class<T> clz) {
        Map<Integer, String> map = new HashMap<>();
        for (T enumConstant : clz.getEnumConstants()) {
            map.put(enumConstant.getCode(), enumConstant.getDesc());
        }
        return map;
    }

    static <T extends Enum<T> & CodedEnum<T>> List<String> getList(Class<T> clz) {
        return Arrays.stream(clz.getEnumConstants()).map(CodedEnum::getDesc).collect(Collectors.toList());
    }


}